home *** CD-ROM | disk | FTP | other *** search
- /*
- File: RTPMPIMAAudio.c
-
- Contains: Definition of IMA Audio RTPMediaPacketizer
-
- Copyright: © 1997-1999 by Apple Computer, Inc., all rights reserved.
-
-
-
- OVERVIEW
-
- QuickTime Streaming software uses an RTPMediaPacketizer to encapsulate
- sample data in network packets. When preparing to packetize sample data,
- Streaming software first determines a packetizer's capabilities and
- operational parameters. If the packetizer is suitable, the Streaming
- software provides the packetizer with an RTPPacketBuilder. The packetizer
- uses the RTPPacketBuilder to construct network packets from sample data.
- The Streaming software specifies what sample data to packetize by calling
- the packetizer's RTPMPSetSampleData() implementation.
-
- This packetizer implements the following interface and delegates all other
- calls to a base RTPMediaPacketizer defined by QuickTime Streaming.
-
-
- STANDARD COMPONENT INTERFACE
- ----------------------------
-
- CallComponentOpen() Allocate and initialize storage for
- instance variables.
-
- CallComponentClose() Reverse the effects of
- CallComponentOpen().
-
- CallComponentVersion() Return the instance's version.
-
- CallComponentTarget() Update the instance's inheritance graph.
-
-
-
- RTP MEDIA PACKETIZER INTERFACE
- ------------------------------
-
- RTPMPInitialize() Prepare to packetize sample data.
-
- RTPMPPreflightMedia() Determine whether the packetizer can
- packetize the described data.
-
- RTPMPSetSampleData() Use the instance's RTPPacketBuilder to
- packetize sample data.
-
- RTPMPFlush() Finish any packetization in progress.
-
- RTPMPReset() Abort any packetization in progress.
-
- RTPMPGetInfo() Return the requested information.
-
- RTPMPSetTimeScale()
-
- RTPMPGetTimeScale()
-
- RTPMPSetTimeBase()
-
- RTPMPGetTimeBase()
-
- RTPMPHasCharacteristic()
-
- RTPMPSetPacketBuilder()
-
- RTPMPGetPacketBuilder()
-
- RTPMPSetMediaType()
-
- RTPMPGetMediaType()
-
- RTPMPSetMaxPacketSize()
-
- RTPMPGetMaxPacketSize()
-
- RTPMPSetMaxPacketDuration()
-
- RTPMPGetMaxPacketDuration()
-
- RTPMPDoUserDialog() Present a dialog of user-adjustable
- options.
-
- RTPMPSetSettingsFromAtomContainerAtAtom()
- Update instance variables with saved
- user settings.
-
- RTPMPGetSettingsIntoAtomContainerAtAtom()
- Return current settings of user
- adjustable options.
-
- RTPMPGetMediaSettingsAsText() Return current settings of user
- adjustable options as a string.
- */
-
-
-
- /* ---------------------------------------------------------------------------
- * H E A D E R S
- * ---------------------------------------------------------------------------
- */
-
- #include "RTPMPIMAAudio.h"
- #include "RTPMPIMAAudioResources.h"
- #include <FixMath.h>
- #include <Math64.h>
- #include <Resources.h>
- #include <TextUtils.h>
-
-
-
- /* ---------------------------------------------------------------------------
- * R T P M E D I A P A C K E T I Z E R P R O T O T Y P E S
- * ---------------------------------------------------------------------------
- *
- * QTStreamingComponents.k.h uses these macros to declare prototypes for
- * the RTPMediaPacketizer calls defined in this file.
- *
- */
-
- #define RTPMP_BASENAME() RTPMPIMAAudio_
- #define RTPMP_GLOBALS() RTPMPIMAAudioInstanceData **
-
- #include <QTStreamingComponents.k.h>
-
-
-
- /* ---------------------------------------------------------------------------
- * C O M P O N E N T D I S P A T C H H E L P E R
- * ---------------------------------------------------------------------------
- *
- * ComponentDispatchHelper.c uses these macros to define a dispatcher and to
- * declare prototypes for the core component calls defined in this file. For
- * Mac OS, it defines the routine descriptor that serves as the component
- * entry point. The name of the routine descriptor is the macro expansion of
- *
- * CALLCOMPONENT_BASENAME()##ComponentDispatchRD
- *
- * The name of the dispatcher is the macro expansion of
- *
- * CALLCOMPONENT_BASENAME()##ComponentDispatch
- *
- */
-
- #define CALLCOMPONENT_BASENAME() RTPMP_BASENAME()
- #define CALLCOMPONENT_GLOBALS() RTPMP_GLOBALS() storage
- #define COMPONENT_DISPATCH_FILE "RTPMPIMAAudioDispatch.h"
- #define COMPONENT_C_DISPATCHER 1
- #define COMPONENT_UPP_SELECT_ROOT() RTPMP
- #define GET_DELEGATE_COMPONENT() ( ( **storage ).itsBase )
-
- #include <ComponentDispatchHelper.c>
-
-
-
- #pragma mark * INTERNAL IMPLEMENTATION
- #pragma mark -
- /* ---------------------------------------------------------------------------
- * I N T E R N A L I M P L E M E N T A T I O N
- * ---------------------------------------------------------------------------
- */
-
- #if TARGET_OS_WIN32
- # define DragWindow( window, startPt, boundsRect )
- #endif
-
-
-
- enum
- {
- __kNoFlags = 0,
- __kFlush = true,
- __kDontFlush = !__kFlush,
- __kDefaultPacketDurationLimit = 200, /* 200ms. See RFC 1890, section 4.1 */
- __kDefaultInterleaveCount = 3,
- __kTypicalMTUSize = 1500, /* Ethernet */
- __kTypicalNetworkHeaderSize = 20, /* IP, no options */
- __kTypicalTransportHeaderSize = 8, /* UDP */
- __kTypicalRTPHeaderSize = 12, /* no CSRCs, no extension */
- __kDefaultPacketSizeLimit =
- __kTypicalMTUSize - __kTypicalNetworkHeaderSize - __kTypicalTransportHeaderSize -
- __kTypicalRTPHeaderSize
- };
-
- enum
- {
- __kOKButton = 1,
- __kCancelButton = 2,
- __kInterleavingMenu = 3
- };
-
- enum
- {
- __kInterleaveCountAtomType = 'ilvc'
- };
-
-
-
- typedef UInt32 __TStoredInterleaveCount;
-
-
-
- /* ---------------------------------------------------------------------------
- * __Drag()
- * ---------------------------------------------------------------------------
- *
- * Drag the dialog window on mouseDown.
- *
- */
-
- static
- Boolean
- __Drag(
- DialogPtr aDialog,
- const EventRecord * anEvent )
- {
- Boolean theResult = false;
- WindowPtr theWindow;
- short thePart;
- Rect theBoundary;
-
-
- if( anEvent->what == mouseDown )
- {
- thePart = MacFindWindow( anEvent->where, &theWindow );
-
- if( theWindow == aDialog && thePart == inDrag )
- {
- theBoundary = ( **GetGrayRgn() ).rgnBBox;
-
- DragWindow( aDialog, anEvent->where, &theBoundary );
-
- theResult = true;
- }
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __SettingsDialogFilter()
- * ---------------------------------------------------------------------------
- *
- * Drag the dialog window if appropriate. Otherwise dispatch first to the
- * custom event filter, if any, passed to RTPMPDoUserDialog(), and then, if
- * necessary, to the standard event filter.
- *
- */
-
- static
- pascal
- Boolean
- __SettingsDialogFilter(
- DialogPtr aDialog,
- EventRecord * anEvent,
- short * anItem )
- {
- Boolean theResult = false;
- ModalFilterUPP theCustomFilter;
-
-
- if( __Drag( aDialog, anEvent ) )
- {
- *anItem = 0;
- theResult = true;
- }
-
- else
- {
- theCustomFilter = REINTERPRET_CAST( ModalFilterUPP )( GetWRefCon( aDialog ) );
-
- if( theCustomFilter )
- theResult = CallModalFilterProc( theCustomFilter, aDialog, anEvent, anItem );
-
- if( !theResult )
- theResult = StdFilterProc( aDialog, anEvent, anItem );
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __GreatestCommonFactor()
- * ---------------------------------------------------------------------------
- *
- * Compute the greatest common factor of two positive integers.
- *
- */
-
- static
- UInt32
- __GreatestCommonFactor(
- UInt32 inDividend,
- UInt32 inDivisor )
- {
- UInt32 theRemainder;
-
-
- while( inDivisor )
- {
- theRemainder = inDividend % inDivisor;
- inDividend = inDivisor;
- inDivisor = theRemainder;
- }
-
- return( inDividend );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __LockInstanceData()
- * ---------------------------------------------------------------------------
- *
- * Lock relocatable block containing instance data.
- *
- */
-
- static
- void
- __LockInstanceData(
- RTPMPIMAAudioInstanceData ** inGlobals )
- {
- if( !( **inGlobals ).itsLockCount )
- {
- if( ( **inGlobals ).itsInSystemHeap )
- HLock( REINTERPRET_CAST( Handle )( inGlobals ) );
- else
- HLockHi( REINTERPRET_CAST( Handle )( inGlobals ) );
- }
-
- ( **inGlobals ).itsLockCount++;
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __UnlockInstanceData()
- * ---------------------------------------------------------------------------
- *
- * Unlock relocatable block containing instance data.
- *
- */
-
- static
- void
- __UnlockInstanceData(
- RTPMPIMAAudioInstanceData ** inGlobals )
- {
- --( **inGlobals ).itsLockCount;
-
- if( !( **inGlobals ).itsLockCount )
- HUnlock( REINTERPRET_CAST( Handle )( inGlobals ) );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __InterleaveGroupFrameCount()
- * ---------------------------------------------------------------------------
- *
- * Compute the number of frames in an interleave group according to the
- * following constraints:
- *
- * - no packet exceeds the packet size limit
- *
- * - no packet exceeds the packet duration limit
- *
- * - the frame count is a multiple of the channel count
- *
- * - the group duration is an integer number of clock cycles
- *
- */
-
- static
- UInt32
- __InterleaveGroupFrameCount(
- RTPMPIMAAudioInstanceData ** inGlobals )
- {
- UInt32 theResult;
- UInt64 theDurationLimit;
- UInt64 theSampleRate;
- UInt32 theTimewiseLimit;
- UInt32 theInterleaveCount;
- UInt32 theChannelCount;
- UInt32 theFrameDurationRemainder;
- UInt32 theIntegerDurationFrameCount;
- UInt32 theConstrainingFactor;
- UInt32 theCommonFactor;
-
-
- /* Compute size-wise limit per payload. */
-
- theResult =
- ( ( **inGlobals ).itsPayloadSizeLimit -
- ( sizeof( IMAAudioPayload ) - sizeof( IMAAudioFrame ) ) ) /
- sizeof( IMAAudioFrame );
-
-
- /* Compute time-wise limit per payload. */
-
- theDurationLimit = U64SetU( ( **inGlobals ).itsPayloadDurationLimit );
- theSampleRate =
- U64SetU( IMAAudioPayloadSampleRate( &( **inGlobals ).itsPayloadAttributes ) );
-
- theTimewiseLimit =
- Fix2Long(
- U32SetU(
- U64Div(
- U64Multiply( theDurationLimit, theSampleRate ),
- U64SetU( 1000UL * kIMAAudioPayloadFrameSampleCount ) ) ) );
-
-
- /* Select lesser limit. */
-
- if( theResult > theTimewiseLimit )
- theResult = theTimewiseLimit;
-
-
- /* Compute limit for entire interleave group. */
-
- theInterleaveCount =
- IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes );
-
- theResult *= theInterleaveCount;
-
-
- /* Compute the least number of frames that, given their sample rate,
- have an integer duration with respect to the RTP clock rate of
- 55125 Hz. As explained in IMAAudioPayload.h, the integer-duration
- frame count will be no greater than four. An interleave group has
- integer duration when its frame count is a multiple of the integer-
- duration frame count. */
-
- theFrameDurationRemainder =
- U64Mod(
- U64Multiply(
- U64SetU( STATIC_CAST( UInt32 )( kIMAAudioPayloadRTPTimeScale ) << 16 ),
- U64SetU( kIMAAudioPayloadFrameSampleCount ) ),
- theSampleRate );
-
- if( theFrameDurationRemainder )
- {
- theIntegerDurationFrameCount =
- U32SetU( U64Div( theSampleRate, theFrameDurationRemainder ) );
- }
-
- else
- {
- theIntegerDurationFrameCount = 1;
- }
-
-
- /* Restrict group frame count to a multiple of both the channel count and
- the integer-duration frame count. */
-
- theChannelCount = IMAAudioPayloadChannelCount( &( **inGlobals ).itsPayloadAttributes );
-
- theCommonFactor =
- __GreatestCommonFactor( theIntegerDurationFrameCount, theChannelCount );
-
- theConstrainingFactor =
- ( theIntegerDurationFrameCount / theCommonFactor ) *
- ( theChannelCount / theCommonFactor );
-
- theResult = ( theResult / theConstrainingFactor ) * theConstrainingFactor;
-
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __UpdateLimits()
- * ---------------------------------------------------------------------------
- *
- * Update values used to construct network packets.
- *
- */
-
- static
- void
- __UpdateLimits(
- RTPMPIMAAudioInstanceData ** inGlobals )
- {
- if( ( **inGlobals ).itsPayloadAttributesInitialized )
- {
- /* Update count of frames in each interleave group. */
-
- ( **inGlobals ).itsInterleaveGroupFrameCount =
- __InterleaveGroupFrameCount( inGlobals );
- }
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __UpdateSampleDescription()
- * ---------------------------------------------------------------------------
- *
- * Determine whether the SampleDescription of incoming sample data has
- * changed and update instance variables accordingly.
- *
- */
-
- static
- ComponentResult
- __UpdateSampleDescription(
- RTPMPIMAAudioInstanceData ** inGlobals,
- const RTPMPSampleDataParams * inSampleData )
- {
- ComponentResult theError = noErr;
- SInt32 theFlags;
- SoundDescriptionHandle theDescription;
- CompressionInfo theCompressionInfo;
- UnsignedFixed thePayloadSampleRate;
-
-
- /* Check the SampleDescription if it is the first description or if the cached
- sample description seed doesn't match the current seed. */
-
- if(
- !( **inGlobals ).itsPayloadAttributesInitialized ||
- ( **inGlobals ).itsSampleDescriptionSeed != inSampleData->sampleDescSeed )
- {
- /* If the RTPMPSetSampleData() implementation queues data, then any
- queued sample data, which uses the obsolete SampleDescription, must
- be flushed before updating to the new SampleDescription. */
-
- theError = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
-
- if( !theError )
- {
- theDescription =
- REINTERPRET_CAST( SoundDescriptionHandle )(
- inSampleData->sampleDescription );
-
- theError =
- GetCompressionInfo(
- fixedCompression, ( **theDescription ).dataFormat,
- ( **theDescription ).numChannels, ( **theDescription ).sampleSize,
- &theCompressionInfo );
-
-
- /* Update the payload header that the packetizer includes in each network
- packet. */
-
- IMAAudioPayloadSetChannelCount(
- &( **inGlobals ).itsPayloadAttributes, ( **theDescription ).numChannels );
-
- thePayloadSampleRate =
- IMAAudioPayloadSetSampleRate(
- &( **inGlobals ).itsPayloadAttributes,
- ( **theDescription ).sampleRate );
-
- ( **inGlobals ).itsPayloadAttributesInitialized = true;
-
-
- IMAAudioQueueSetFlowControl(
- &( **inGlobals ).itsAudioQueue, ( **theDescription ).sampleRate,
- thePayloadSampleRate, ( **theDescription ).numChannels );
-
-
- /* Update values used to construct network packets. */
-
- __UpdateLimits( inGlobals );
-
-
- /* Update the cached sample description seed to indicate that the
- packetizer state is now consistent with the new SampleDescription. */
-
- ( **inGlobals ).itsSampleDescriptionSeed = inSampleData->sampleDescSeed;
- }
- }
-
- return( theError );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __SampleBlockDuration()
- * ---------------------------------------------------------------------------
- *
- * Compute the duration of the described sample block.
- *
- */
-
- static
- UInt32
- __SampleBlockDuration(
- const RTPMPSampleDataParams * inSampleData )
- {
- UInt32 theResult;
- UInt32 theSampleCount;
- SoundDescriptionHandle theDescription;
- UInt64 theFixedSampleCount;
-
-
- if( inSampleData->duration )
- {
- theResult = inSampleData->duration;
- }
-
- else
- {
- theDescription =
- REINTERPRET_CAST( SoundDescriptionHandle )( inSampleData->sampleDescription );
-
- theSampleCount =
- kIMAAudioPayloadFrameSampleCount *
- ( inSampleData->dataLength / sizeof( IMAAudioFrame ) );
-
- theFixedSampleCount = U64Multiply( U64SetU( theSampleCount ), U64SetU( fixed1 ) );
-
- theResult =
- U32SetU(
- U64Div(
- U64Multiply(
- theFixedSampleCount, U64SetU( kIMAAudioPayloadRTPTimeScale ) ),
- U64SetU( ( **theDescription ).sampleRate ) ) );
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __BeginInterleaveGroup()
- * ---------------------------------------------------------------------------
- *
- * Use the RTPPacketBuilder to create a new packet group and all the packets
- * in that group. For this packetizer, a packet group contains one
- * interleave group.
- *
- * Each network packet consists of a fixed header followed by sample data.
- * This function adds the fixed header to each packet.
- *
- */
-
- static
- ComponentResult
- __BeginInterleaveGroup(
- const IMAAudioPayload * inPayloadAttributes,
- TimeValue64 inTimestamp,
- UInt32 inFrameCount,
- RTPPacketBuilder inPacketBuilder,
- RTPPacketGroupRef * outPacketGroup,
- RTPPacketRef * outPackets )
- {
- ComponentResult theResult;
- UInt32 theInterleaveCount;
- UInt32 thePayloadFrameCount;
- UInt32 theIndex;
- IMAAudioPayload theHeader;
- UInt32 theHeaderSize;
- UInt32 thePayloadSizeLimit;
-
-
- theResult =
- RTPPBBeginPacketGroup( inPacketBuilder, __kNoFlags, inTimestamp, outPacketGroup );
-
- theInterleaveCount = IMAAudioPayloadInterleaveCount( inPayloadAttributes );
- thePayloadFrameCount = ( inFrameCount + theInterleaveCount - 1 ) / theInterleaveCount;
-
- theHeader = *inPayloadAttributes;
- theHeaderSize = sizeof( theHeader ) - sizeof( IMAAudioFrame );
-
- thePayloadSizeLimit =
- theHeaderSize + ( thePayloadFrameCount * sizeof( IMAAudioFrame ) );
-
-
- /* If there aren't enough frames to fill an entire interleave group, omit the
- empty packets. */
-
- if( theInterleaveCount > inFrameCount )
- theInterleaveCount = inFrameCount;
-
- for( theIndex = 0; theIndex < theInterleaveCount && theResult == noErr; theIndex++ )
- {
- theResult =
- RTPPBBeginPacket(
- inPacketBuilder, __kNoFlags, *outPacketGroup, thePayloadSizeLimit,
- &outPackets[ theIndex ] );
-
- if( theResult == noErr )
- {
- /* The header is added to the network packet as literal data. Literal
- data is written directly to the network packet. If the
- RTPPacketBuilder is storing network packet data to disk, it must
- store a copy of literal data. */
-
- theResult =
- RTPPBAddPacketLiteralData(
- inPacketBuilder, __kNoFlags, *outPacketGroup, outPackets[ theIndex ],
- REINTERPRET_CAST( UInt8 * )( &theHeader ), theHeaderSize, NULL );
-
- IMAAudioPayloadIncrementInterleaveIndex( &theHeader );
- }
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __EndInterleaveGroup()
- * ---------------------------------------------------------------------------
- *
- * Use the RTPPacketBuilder to close the current packet group and all its
- * packets.
- *
- */
-
- static
- ComponentResult
- __EndInterleaveGroup(
- const IMAAudioPayload * inPayloadAttributes,
- UInt32 inFrameCount,
- RTPPacketBuilder inPacketBuilder,
- RTPPacketGroupRef inPacketGroup,
- const RTPPacketRef * inPackets )
- {
- ComponentResult theResult = noErr;
- UnsignedFixed theSampleRate;
- UInt32 theDuration;
- UInt32 theInterleaveCount;
- UInt32 theIndex;
-
-
- theSampleRate = IMAAudioPayloadSampleRate( inPayloadAttributes );
-
- theDuration =
- U32SetU(
- U64Div(
- U64Multiply(
- U64SetU( inFrameCount * kIMAAudioPayloadFrameSampleCount ),
- U64SetU( STATIC_CAST( UInt32 )( kIMAAudioPayloadRTPTimeScale ) << 16 ) ),
- U64SetU( theSampleRate ) ) );
-
- theDuration /= IMAAudioPayloadChannelCount( inPayloadAttributes );
-
- theInterleaveCount = IMAAudioPayloadInterleaveCount( inPayloadAttributes );
-
-
- /* If there aren't enough frames to fill an entire interleave group, the empty
- packets have been omitted. */
-
- if( theInterleaveCount > inFrameCount )
- theInterleaveCount = inFrameCount;
-
-
- /* To simplify reassembly, this packetizer uses the timestamp of the start
- of the group as the timestamp for each network packet in the group. When
- reassembling, the derived RTPReassembler relies on the QuickTime Streaming
- base RTPReassembler to group together packets that have the same timestamp.
-
- A packet's duration is the time between its timestamp and the timestamp
- of the next packet. Since these packets share the same timestamp, most
- have zero duration. The last packet in the group reflects the duration
- of the entire group. */
-
- for(
- theIndex = 0; theIndex < ( theInterleaveCount - 1 ) && theResult == noErr;
- theIndex++ )
- {
- theResult =
- RTPPBEndPacket(
- inPacketBuilder, __kNoFlags, inPacketGroup, inPackets[ theIndex ],
- 0 /* inTimeOffset */ , 0 /* inDuration */ );
- }
-
- if( theResult == noErr )
- {
- /* The packetizer sets the RTP/AVP marker bit in the last network
- packet of an interleave group. The QuickTime Streaming base
- RTPReassembler can better assist in reassembling the payload data
- if this bit is used to mark the end of a packet group. */
-
- theResult =
- RTPPBEndPacket(
- inPacketBuilder, kRTPPBSetMarkerFlag, inPacketGroup, inPackets[ theIndex ],
- 0, theDuration );
-
- if( theResult == noErr )
- {
- /* For this packetizer, every group contains only sync samples. That
- means the sample data for the group can be decoded independently of
- any previous sample data. When randomly accessing stored movies,
- a streaming server can look for sync samples. */
-
- theResult =
- RTPPBEndPacketGroup( inPacketBuilder, kRTPPBSyncSampleFlag, inPacketGroup );
- }
-
- else
- {
- RTPPBEndPacketGroup( inPacketBuilder, kRTPPBDontSendFlag, inPacketGroup );
- }
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __PacketizeInterleaveGroup()
- * ---------------------------------------------------------------------------
- *
- * Use the RTPPacketBuilder and the queued sample data to construct a single
- * interleave group of network packets.
- *
- */
-
- static
- ComponentResult
- __PacketizeInterleaveGroup(
- IMAAudioQueue * inAudioQueue,
- const IMAAudioPayload * inPayloadAttributes,
- UInt32 inInterleaveGroupFrameCount,
- RTPPacketBuilder inPacketBuilder )
- {
- ComponentResult theResult;
- IMAAudioPayload thePayloadAttributes;
- UInt32 theFrameCount;
- UInt32 theInterleaveCount;
- IMAAudioQueueElement theFrameInfo;
- RTPPacketGroupRef thePacketGroup;
- RTPPacketRef thePackets[ kIMAAudioPayloadInterleaveCountLimit ];
- UInt32 theFrameIndex;
-
-
- /* Get the total queued frame count. */
-
- theFrameCount = IMAAudioQueueCount( inAudioQueue );
-
- if( theFrameCount )
- {
- /* Limit the frame count to a single interleave group. */
-
- if( theFrameCount >= inInterleaveGroupFrameCount )
- theFrameCount = inInterleaveGroupFrameCount;
-
- thePayloadAttributes = *inPayloadAttributes;
-
- theInterleaveCount = IMAAudioPayloadInterleaveCount( &thePayloadAttributes );
-
- IMAAudioPayloadSetInterleaving(
- &thePayloadAttributes, theInterleaveCount, theFrameCount );
-
-
- /* Initialize the interleave group. */
-
- IMAAudioQueueDequeue( inAudioQueue, &theFrameInfo );
-
- theResult =
- __BeginInterleaveGroup(
- &thePayloadAttributes, theFrameInfo.itsTimestamp, theFrameCount,
- inPacketBuilder, &thePacketGroup, thePackets );
-
-
- /* Interleave audio frames into network packets. */
-
- theFrameIndex = 0;
-
- do
- {
- /* The RTPPacketBuilder provides a routine specifically for adding
- sample data. For stored movies, the RTPPacketBuilder need not
- store a copy of sample data, since the data is already stored
- in the movie. */
-
- theResult =
- RTPPBAddPacketSampleData(
- inPacketBuilder, __kNoFlags, thePacketGroup,
- thePackets[ theFrameIndex % theInterleaveCount ],
- theFrameInfo.itsSampleDataParams, theFrameInfo.itsOffset,
- sizeof( IMAAudioFrame ), NULL );
-
- theFrameIndex++;
- }
- while(
- theResult == noErr && theFrameIndex < theFrameCount &&
- IMAAudioQueueDequeue( inAudioQueue, &theFrameInfo ) );
-
-
- /* End the interleave group. */
-
- if( theResult == noErr )
- {
- theResult =
- __EndInterleaveGroup(
- &thePayloadAttributes, theFrameCount, inPacketBuilder,
- thePacketGroup, thePackets );
- }
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * __ProcessAudioQueue()
- * ---------------------------------------------------------------------------
- *
- * When flushing, packetize all queued audio data. Otherwise, packetize
- * interleave groups continuously until there is not enough data to fill an
- * interleave group.
- *
- */
-
- static
- ComponentResult
- __ProcessAudioQueue(
- RTPMPIMAAudioInstanceData ** inGlobals,
- Boolean inFlush )
- {
- ComponentResult theResult = noErr;
- IMAAudioPayload thePayloadAttributes = ( **inGlobals ).itsPayloadAttributes;
- UInt32 theMinimumFrameCount;
- UInt32 theFrameCount;
-
-
- __LockInstanceData( inGlobals );
-
- if( inFlush )
- theMinimumFrameCount = 1;
- else
- theMinimumFrameCount = ( **inGlobals ).itsInterleaveGroupFrameCount;
-
- for(
- theFrameCount = IMAAudioQueueCount( &( **inGlobals ).itsAudioQueue );
- theFrameCount >= theMinimumFrameCount && theResult == noErr;
- theFrameCount = IMAAudioQueueCount( &( **inGlobals ).itsAudioQueue ) )
- {
- if( theFrameCount > ( **inGlobals ).itsInterleaveGroupFrameCount )
- theFrameCount = ( **inGlobals ).itsInterleaveGroupFrameCount;
-
- theResult =
- __PacketizeInterleaveGroup(
- &( **inGlobals ).itsAudioQueue, &thePayloadAttributes, theFrameCount,
- ( **inGlobals ).itsPacketBuilder );
- }
-
- __UnlockInstanceData( inGlobals );
-
- return( theResult );
- }
-
-
-
- #pragma mark -
- #pragma mark * STANDARD COMPONENT INTERFACE
- #pragma mark -
- /* ---------------------------------------------------------------------------
- * S T A N D A R D C O M P O N E N T I N T E R F A C E
- * ---------------------------------------------------------------------------
- */
-
- /* ---------------------------------------------------------------------------
- * + CallComponentOpen() implementation
- * ---------------------------------------------------------------------------
- *
- * Allocate and initialize storage for instance variables. When a packetizer
- * is opened, it is not always called to packetize data, so this function
- * doesn't perform any allocations or time-consuming operations that are
- * needed only for packetizing sample data. The RTPMPInitialize()
- * implementation performs such operations.
- *
- * Since the RTPMPGetSettingsAsText() implementation and the
- * RTPMPDoUserDialog() implementation might be called before calling the
- * RTPMPInitialize() implementation, this function must initialize any
- * instance variables used by those functions.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Open(
- RTPMPIMAAudioInstanceData ** inGlobals,
- ComponentInstance self )
- {
- ComponentResult theResult = noErr;
- RTPMediaPacketizer theBase;
-
-
- inGlobals =
- REINTERPRET_CAST( RTPMPIMAAudioInstanceData ** )(
- NewHandleClear( sizeof( **inGlobals ) ) );
-
- if( inGlobals )
- {
- ( **inGlobals ).itself = self;
- ( **inGlobals ).itsFinalDerivation = self;
- ( **inGlobals ).itsInSystemHeap =
- ( HandleZone( REINTERPRET_CAST( Handle )( inGlobals ) ) == SystemZone() );
- ( **inGlobals ).itsLockCount = 0;
- ( **inGlobals ).itsInitialized = false;
- ( **inGlobals ).itsPayloadAttributesInitialized = false;
-
- IMAAudioPayloadInitialize( &( **inGlobals ).itsPayloadAttributes );
-
- SetComponentInstanceStorage( self, REINTERPRET_CAST( Handle )( inGlobals ) );
-
- theResult =
- OpenADefaultComponent(
- kRTPMediaPacketizerType, kRTPBaseMediaPacketizerType, &theBase );
-
- if( theResult == noErr )
- {
- ( **inGlobals ).itsBase = theBase;
- theResult = CallComponentTarget( ( **inGlobals ).itsBase, self );
- }
- }
-
- else
- {
- theResult = MemError();
-
- if( theResult == noErr )
- theResult = memFullErr;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + CallComponentClose() implementation
- * ---------------------------------------------------------------------------
- *
- * Reverse the effects of the CallComponentOpen() implementation.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Close(
- RTPMPIMAAudioInstanceData ** inGlobals,
- ComponentInstance self )
- {
- #pragma unused( self )
-
- IMAAudioQueue theAudioQueue;
-
-
- if( inGlobals )
- {
- if( ( **inGlobals ).itsInitialized )
- {
- theAudioQueue = ( **inGlobals ).itsAudioQueue;
- IMAAudioQueueFlush( &theAudioQueue );
- }
-
- if( ( **inGlobals ).itsBase )
- CloseComponent( ( **inGlobals ).itsBase );
-
- DisposeHandle( REINTERPRET_CAST( Handle )( inGlobals ) );
- }
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + CallComponentVersion() implementation
- * ---------------------------------------------------------------------------
- *
- * Return the instance's version.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Version(
- RTPMPIMAAudioInstanceData ** inGlobals )
- {
- #pragma unused( inGlobals )
-
- return( kComponentVersion );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + CallComponentTarget() implementation
- * ---------------------------------------------------------------------------
- *
- * Update the instance's inheritance graph with a new most-derived instance.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Target(
- RTPMPIMAAudioInstanceData ** inGlobals,
- ComponentInstance target )
- {
- ComponentResult theResult;
-
-
- if( ( **inGlobals ).itsBase )
- theResult = ComponentSetTarget( ( **inGlobals ).itsBase, target );
- else
- theResult = noErr;
-
- if( theResult == noErr )
- ( **inGlobals ).itsFinalDerivation = target;
-
- return( theResult );
- }
-
-
-
- #pragma mark -
- #pragma mark * RTP MEDIA PACKETIZER INTERFACE
- #pragma mark -
- /* ---------------------------------------------------------------------------
- * R T P M E D I A P A C K E T I Z E R I N T E R F A C E
- * ---------------------------------------------------------------------------
- */
-
- /* ---------------------------------------------------------------------------
- * + RTPMPInitialize() implementation
- * ---------------------------------------------------------------------------
- *
- * Prepare to packetize sample data. This implementation initializes
- * instance variables that represent the packetization state.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Initialize(
- RTPMPIMAAudioInstanceData ** inGlobals,
- SInt32 inFlags )
- {
- ComponentResult theResult;
-
-
- if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPInitializeSelect ) )
- theResult = RTPMPInitialize( ( **inGlobals ).itsBase, inFlags );
- else
- theResult = noErr;
-
- if( theResult == noErr )
- {
- ( **inGlobals ).itsExpectedTimestamp = 0;
- ( **inGlobals ).itsPacketBuilder = NULL;
- ( **inGlobals ).itsPayloadSizeLimit = __kDefaultPacketSizeLimit;
- ( **inGlobals ).itsPayloadDurationLimit = __kDefaultPacketDurationLimit;
- ( **inGlobals ).itsInterleaveGroupFrameCount = 0;
-
- IMAAudioQueueInitialize( &( **inGlobals ).itsAudioQueue );
-
- ( **inGlobals ).itsInitialized = true;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPPreflightMedia() implementation
- * ---------------------------------------------------------------------------
- *
- * Determine whether the packetizer can packetize data described by the
- * given SampleDescription. This implementation verifies that the sample
- * data is in IMA Audio format.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_PreflightMedia(
- RTPMPIMAAudioInstanceData ** inGlobals,
- OSType inMediaType,
- SampleDescriptionHandle inSampleDescription )
- {
- #pragma unused( inGlobals )
-
- ComponentResult theResult;
- SoundDescriptionHandle theDescription;
-
-
- theDescription = REINTERPRET_CAST( SoundDescriptionHandle )( inSampleDescription );
-
- if(
- inMediaType != SoundMediaType ||
- ( **theDescription ).dataFormat != kIMACompression )
- {
- theResult = qtsUnsupportedDataTypeErr;
- }
-
- else
- {
- theResult = noErr;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetSampleData() implementation
- * ---------------------------------------------------------------------------
- *
- * Use the instance's RTPPacketBuilder to packetize the sample data described
- * by the RTPMPSampleDataParams parameter. The sample time of the data in
- * successive calls is non-decreasing, but could be non-contiguous--that is,
- * the data might have gaps. This implementation guarantees that any queued
- * data is always contiguous by flushing when it detects non-contiguous data.
- *
- * The RTPMPSampleDataParams structure includes a SampleDescription. This
- * implementation calls __UpdateSampleDescription() to detect when the
- * SampleDescription changes and to make any updates necessary to accomodate
- * the new SampleDescription.
- *
- * The function then queues the sample data parameters and calls
- * __ProcessAudioQueue() to packetize queued sample data.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetSampleData(
- RTPMPIMAAudioInstanceData ** inGlobals,
- const RTPMPSampleDataParams * inSampleData,
- SInt32 * outFlags )
- {
- ComponentResult theResult;
- SInt32 theFlags;
-
-
- /* Ignore requests that have no data */
-
- if( inSampleData->dataLength )
- {
- /* Flush before queueing non-contiguous data. */
-
- if( inSampleData->timeStamp != ( **inGlobals ).itsExpectedTimestamp )
- theResult = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
- else
- theResult = noErr;
-
- if( theResult == noErr )
- {
- theResult = __UpdateSampleDescription( inGlobals, inSampleData );
-
- if( theResult == noErr )
- {
- __LockInstanceData( inGlobals );
- IMAAudioQueueEnqueue( &( **inGlobals ).itsAudioQueue, inSampleData );
- __UnlockInstanceData( inGlobals );
-
- theResult = __ProcessAudioQueue( inGlobals, __kDontFlush );
-
- if( theResult == noErr )
- {
- ( **inGlobals ).itsExpectedTimestamp =
- inSampleData->timeStamp + __SampleBlockDuration( inSampleData );
- }
- }
- }
- }
-
- *outFlags = 0;
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPFlush() implementation
- * ---------------------------------------------------------------------------
- *
- * Finish any packetization in progress.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Flush(
- RTPMPIMAAudioInstanceData ** inGlobals,
- SInt32 inFlags,
- SInt32 * outFlags )
- {
- ComponentResult theResult;
-
-
- theResult = __ProcessAudioQueue( inGlobals, __kFlush );
-
- __LockInstanceData( inGlobals );
- IMAAudioQueueFlush( &( **inGlobals ).itsAudioQueue );
- __UnlockInstanceData( inGlobals );
-
- ( **inGlobals ).itsExpectedTimestamp = 0;
-
- if(
- theResult == noErr &&
- CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPFlushSelect ) )
- {
- theResult = RTPMPFlush( ( **inGlobals ).itsBase, inFlags, outFlags );
- }
-
- else
- {
- *outFlags = 0;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPReset() implementation
- * ---------------------------------------------------------------------------
- *
- * Abort any packetization in progress and prepare to packetize a new,
- * possibly unrelated, data stream. This implementation flushes its audio
- * data queue, invalidates its cached payload attributes, and resets its
- * base.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_Reset(
- RTPMPIMAAudioInstanceData ** inGlobals,
- SInt32 inFlags )
- {
- ComponentResult theResult;
-
-
- __LockInstanceData( inGlobals );
- IMAAudioQueueFlush( &( **inGlobals ).itsAudioQueue );
- __UnlockInstanceData( inGlobals );
-
- ( **inGlobals ).itsExpectedTimestamp = 0;
- ( **inGlobals ).itsPayloadAttributesInitialized = false;
-
- if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPResetSelect ) )
- theResult = RTPMPReset( ( **inGlobals ).itsBase, inFlags );
- else
- theResult = noErr;
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetInfo() implementation
- * ---------------------------------------------------------------------------
- *
- * Return the information indicated by the selector. This implemenation
- * computes a result for the following selectors and delegates all others to
- * its base.
- *
- *
- * kRTPMPPayloadTypeInfo ioParams points to an RTPMPPayloadTypeParams
- * structure. This implementation fills in this
- * structure to indicate it uses a dynamic AVP
- * payload type. It copies its payload encoding
- * name to a buffer described by this structure.
- *
- * kRTPMPRTPTimeScaleInfo ioParams points to a TimeScale where the
- * implementation returns the clock rate, in
- * Hertz, to be used for RTP timestamps.
- *
- * kRTPMPMinPayloadSize ioParams points to a UInt32 where the
- * implementation returns the number of octets
- * needed for the fixed header and payload
- * description used by this packetizer.
- *
- * kRTPMPPayloadNameInfo ioParams points to a Str255 where the
- * implementation returns a human-readable name
- * for the payload encoding used by this
- * packetizer.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetInfo(
- RTPMPIMAAudioInstanceData ** inGlobals,
- OSType inSelector,
- void * ioParams )
- {
- ComponentResult theError = noErr;
- RTPMPPayloadTypeParams * thePayloadInfo;
- Str255 theEncodingName;
-
-
- switch( inSelector )
- {
- case kRTPMPPayloadTypeInfo:
- thePayloadInfo = STATIC_CAST( RTPMPPayloadTypeParams * )( ioParams );
- thePayloadInfo->flags = kRTPPayloadTypeDynamicFlag;
- thePayloadInfo->payloadNumber = kRTPPayload_Unknown;
-
- theError =
- GetComponentIndString(
- REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
- theEncodingName, kRTPMPIMAAudioStringListResource,
- kRTPMPIMAAudioProtocolEncodingString );
-
- if( !theError )
- {
- if( thePayloadInfo->nameLength < ( theEncodingName[ 0 ] + 1 ) )
- {
- theError = paramErr;
- }
-
- else
- {
- BlockMoveData(
- &theEncodingName[ 1 ], thePayloadInfo->payloadName,
- theEncodingName[ 0 ] );
-
- thePayloadInfo->payloadName[ theEncodingName[ 0 ] ] = '\0';
- }
-
- thePayloadInfo->nameLength = theEncodingName[ 0 ] + 1;
- }
- break;
-
-
- case kRTPMPRTPTimeScaleInfo:
- *STATIC_CAST( TimeScale * )( ioParams ) = kIMAAudioPayloadRTPTimeScale;
- break;
-
-
- case kRTPMPMinPayloadSize:
- *STATIC_CAST( UInt32 * )( ioParams ) = sizeof( IMAAudioPayload );
- break;
-
-
- case kRTPMPPayloadNameInfo:
- theError =
- GetComponentIndString(
- REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
- STATIC_CAST( StringPtr )( ioParams ),
- kRTPMPIMAAudioStringListResource, kRTPMPIMAAudioHIEncodingString );
- break;
-
-
- case kRTPMPMinPacketDuration:
- theError = qtsBadSelectorErr;
- break;
-
-
- case kRTPMPRequiredSampleDescriptionInfo:
- case kRTPMPSuggestedRepeatPktCountInfo:
- case kRTPMPSuggestedRepeatPktSpacingInfo:
- case kRTPMPMaxPartialSampleSizeInfo:
- case kRTPMPPreferredBufferDelayInfo:
- default:
- theError = RTPMPGetInfo( ( **inGlobals ).itsBase, inSelector, ioParams );
- break;
- }
-
- return( theError );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetTimeScale() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetTimeScale(
- RTPMPIMAAudioInstanceData ** inGlobals,
- TimeScale inTimeScale )
- {
- ( **inGlobals ).itsMediaTimeScale = inTimeScale;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetTimeScale() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetTimeScale(
- RTPMPIMAAudioInstanceData ** inGlobals,
- TimeScale * outTimeScale )
- {
- *outTimeScale = ( **inGlobals ).itsMediaTimeScale;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetTimeBase() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetTimeBase(
- RTPMPIMAAudioInstanceData ** inGlobals,
- TimeBase inTimeBase )
- {
- ( **inGlobals ).itsMediaTimeBase = inTimeBase;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetTimeBase() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetTimeBase(
- RTPMPIMAAudioInstanceData ** inGlobals,
- TimeBase * outTimeBase )
- {
- *outTimeBase = ( **inGlobals ).itsMediaTimeBase;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPHasCharacteristic() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_HasCharacteristic(
- RTPMPIMAAudioInstanceData ** inGlobals,
- OSType inSelector,
- Boolean * outHasIt )
- {
- ComponentResult theResult = noErr;
-
-
- switch( inSelector )
- {
- case kRTPMPNoSampleDataRequiredCharacteristic:
- case kRTPMPHasUserSettingsDialogCharacteristic:
- *outHasIt = true;
- break;
-
-
- case kRTPMPPartialSamplesRequiredCharacteristic:
- case kRTPMPPrefersReliableTransportCharacteristic:
- case kRTPMPRequiresOutOfBandDimensionsCharacteristic:
- *outHasIt = false;
- break;
-
-
- default:
- theResult =
- RTPMPHasCharacteristic( ( **inGlobals ).itsBase, inSelector, outHasIt );
- break;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetPacketBuilder() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetPacketBuilder(
- RTPMPIMAAudioInstanceData ** inGlobals,
- ComponentInstance inPacketBuilder )
- {
- ComponentResult theError;
- SInt32 theFlags;
-
-
- if( ( **inGlobals ).itsInitialized && ( **inGlobals ).itsPacketBuilder )
- theError = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
- else
- theError = noErr;
-
- if( !theError )
- ( **inGlobals ).itsPacketBuilder = inPacketBuilder;
-
- return( theError );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetPacketBuilder() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetPacketBuilder(
- RTPMPIMAAudioInstanceData ** inGlobals,
- ComponentInstance * outPacketBuilder )
- {
- *outPacketBuilder = ( **inGlobals ).itsPacketBuilder;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetMediaType() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetMediaType(
- RTPMPIMAAudioInstanceData ** inGlobals,
- OSType inMediaType )
- {
- #pragma unused( inGlobals )
- ComponentResult theResult;
-
-
- if( inMediaType == SoundMediaType )
- theResult = noErr;
- else
- theResult = qtsBadDataErr;
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetMediaType() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetMediaType(
- RTPMPIMAAudioInstanceData ** inGlobals,
- OSType * outMediaType )
- {
- #pragma unused( inGlobals )
-
- *outMediaType = SoundMediaType;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetMaxPacketSize() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetMaxPacketSize(
- RTPMPIMAAudioInstanceData ** inGlobals,
- UInt32 inMaxPacketSize )
- {
- ( **inGlobals ).itsPayloadSizeLimit = inMaxPacketSize;
-
- __UpdateLimits( inGlobals );
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetMaxPacketSize() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetMaxPacketSize(
- RTPMPIMAAudioInstanceData ** inGlobals,
- UInt32 * outMaxPacketSize )
- {
- *outMaxPacketSize = ( **inGlobals ).itsPayloadSizeLimit;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetMaxPacketDuration() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetMaxPacketDuration(
- RTPMPIMAAudioInstanceData ** inGlobals,
- UInt32 inMaxPacketDuration )
- {
- ( **inGlobals ).itsPayloadDurationLimit = inMaxPacketDuration;
-
- __UpdateLimits( inGlobals );
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetMaxPacketDuration() implementation
- * ---------------------------------------------------------------------------
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetMaxPacketDuration(
- RTPMPIMAAudioInstanceData ** inGlobals,
- UInt32 * outMaxPacketDuration )
- {
- *outMaxPacketDuration = ( **inGlobals ).itsPayloadDurationLimit;
-
- return( noErr );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPDoUserDialog() implementation
- * ---------------------------------------------------------------------------
- *
- * Present a dialog of user-adjustable options and update instance variables
- * according to the user's choices. This implementation allows the user to
- * select an interleave count.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_DoUserDialog(
- RTPMPIMAAudioInstanceData ** inGlobals,
- ModalFilterUPP inFilterUPP,
- Boolean * outCanceled )
- {
- ComponentResult theResult;
- ModalFilterUPP theModalFilter;
- short theItem;
- DialogPtr theDialog;
- short theSavedResources;
- short theResources;
- short theItemType;
- Rect theItemRect;
- ControlHandle theInterleavingMenu;
- UInt32 theInterleaveCount;
-
-
- theModalFilter = NewModalFilterProc( __SettingsDialogFilter );
-
- if( theModalFilter )
- {
- theSavedResources = CurResFile();
-
- theResources =
- OpenComponentResFile( REINTERPRET_CAST( Component )( ( **inGlobals ).itself ) );
-
- if( theResources > 0 )
- {
- theDialog =
- GetNewDialog(
- kRTPMPIMAAudioSettingsDialogResource, NULL,
- REINTERPRET_CAST( WindowPtr )( -1L ) );
-
- if( theDialog )
- {
- SetDialogDefaultItem( theDialog, __kOKButton );
- SetDialogCancelItem( theDialog, __kCancelButton );
-
- GetDialogItem(
- theDialog, __kInterleavingMenu, &theItemType,
- REINTERPRET_CAST( Handle * )( &theInterleavingMenu ), &theItemRect );
-
- theInterleaveCount =
- IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes );
-
- if( theInterleaveCount > 1 )
- theInterleaveCount++;
-
- SetControlValue( theInterleavingMenu, theInterleaveCount );
- HiliteControl( theInterleavingMenu, kControlNoPart );
-
- MacShowWindow( theDialog );
-
- if( theModalFilter )
- SetWRefCon( theDialog, REINTERPRET_CAST( long )( inFilterUPP ) );
- else
- theModalFilter = inFilterUPP;
-
- do
- {
- ModalDialog( theModalFilter, &theItem );
- }
- while( theItem != __kOKButton && theItem != __kCancelButton );
-
- if( theItem == __kOKButton )
- {
- theInterleaveCount = GetControlValue( theInterleavingMenu );
-
- if( theInterleaveCount > 2 )
- --theInterleaveCount;
-
- IMAAudioPayloadSetInterleaving(
- &( **inGlobals ).itsPayloadAttributes, theInterleaveCount, 0 );
- }
-
- *outCanceled = ( theItem == __kCancelButton );
-
- DisposeDialog( theDialog );
- }
-
- else
- {
- theResult = ResError();
-
- if( theResult == noErr )
- theResult = memFullErr;
- }
-
- UseResFile( theSavedResources );
- CloseComponentResFile( theResources );
-
- theResult = noErr;
- }
-
- else
- {
- theResult = ResError();
-
- if( theResult == noErr )
- theResult = memFullErr;
- }
-
- DisposeRoutineDescriptor( theModalFilter );
- }
-
- else
- {
- theResult = MemError();
-
- if( theResult == noErr )
- theResult = memFullErr;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPSetSettingsFromAtomContainerAtAtom() implementation
- * ---------------------------------------------------------------------------
- *
- * Update instance variables according to the saved user settings in the
- * given atom container.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_SetSettingsFromAtomContainerAtAtom(
- RTPMPIMAAudioInstanceData ** inGlobals,
- QTAtomContainer inAtomContainer,
- QTAtom inParentAtom )
- {
- ComponentResult theResult = noErr;
- QTAtom theAtom;
- QTAtomID theAtomID;
- Ptr theAtomData;
- long theDataSize;
- __TStoredInterleaveCount theInterleaveCount;
-
-
- if( inAtomContainer )
- {
- theAtom =
- QTFindChildByIndex(
- inAtomContainer, inParentAtom, __kInterleaveCountAtomType, 1, &theAtomID );
-
- if( theAtom )
- {
- QTLockContainer( inAtomContainer );
-
- QTGetAtomDataPtr(
- inAtomContainer, theAtom, &theDataSize, &theAtomData );
-
- if( theDataSize == sizeof( theInterleaveCount ) )
- {
- /* Convert from storage byte order to platform byte order. */
-
- theInterleaveCount =
- EndianU32_BtoN(
- *REINTERPRET_CAST( __TStoredInterleaveCount * )(
- theAtomData ) );
-
- if( theInterleaveCount > kIMAAudioPayloadInterleaveCountLimit )
- {
- theResult = qtsBadDataErr;
- }
-
- else
- {
- IMAAudioPayloadSetInterleaving(
- &( **inGlobals ).itsPayloadAttributes, theInterleaveCount, 0 );
- }
- }
-
- else
- {
- theResult = qtsBadDataErr;
- }
-
- QTUnlockContainer( inAtomContainer );
- }
- }
-
- else
- {
- theResult = paramErr;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetSettingsIntoAtomContainerAtAtom() implementation
- * ---------------------------------------------------------------------------
- *
- * Return current settings of user-adjustable options in the given atom
- * container.
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetSettingsIntoAtomContainerAtAtom(
- RTPMPIMAAudioInstanceData ** inGlobals,
- QTAtomContainer inOutAtomContainer,
- QTAtom inParentAtom )
- {
- ComponentResult theResult;
- QTAtom theAtom;
- QTAtomID theAtomID;
- __TStoredInterleaveCount theInterleaveCount;
-
-
- if( inOutAtomContainer )
- {
- /* Convert from platform byte order to storage byte order. */
-
- theInterleaveCount =
- EndianU32_NtoB(
- IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes ) );
-
-
- /* If the atom already exists, update it. Otherwise, insert a new one. */
-
- theAtom =
- QTFindChildByIndex(
- inOutAtomContainer, inParentAtom, __kInterleaveCountAtomType, 1, &theAtomID );
-
- if( theAtom )
- {
- theResult =
- QTSetAtomData(
- inOutAtomContainer, theAtom, sizeof( theInterleaveCount ),
- &theInterleaveCount );
- }
-
- else
- {
- theResult =
- QTInsertChild(
- inOutAtomContainer, inParentAtom, __kInterleaveCountAtomType,
- 0 /* id */, 0 /* index */, sizeof( theInterleaveCount ),
- &theInterleaveCount, NULL /* atom */);
- }
- }
-
- else
- {
- theResult = paramErr;
- }
-
- return( theResult );
- }
-
-
-
- /* ---------------------------------------------------------------------------
- * + RTPMPGetMediaSettingsAsText() implementation
- * ---------------------------------------------------------------------------
- *
- * Return current settings of user-adjustable options as a string. This
- * implementation returns the interleave count as colon-delimited name-value
- * pair:
- *
- * "Interleaving: <interleave count>"
- *
- * or
- *
- * "Interleaving: None"
- *
- */
-
- EXTERN_API( ComponentResult )
- RTPMPIMAAudio_GetSettingsAsText(
- RTPMPIMAAudioInstanceData ** inGlobals,
- Handle * text )
- {
- ComponentResult theResult;
- Str255 theSettings;
- UInt32 theInterleaveCount;
- unsigned char theSavedCharacter;
- int theLength;
-
-
- theResult =
- GetComponentIndString(
- REINTERPRET_CAST( Component )( ( **inGlobals ).itself ), theSettings,
- kRTPMPIMAAudioStringListResource, kRTPMPIMAAudioSettingsString );
-
- if( theResult == noErr )
- {
- theLength = theSettings[ 0 ];
- theSavedCharacter = theSettings[ theLength ];
-
- theInterleaveCount =
- IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes );
-
- if( theInterleaveCount > 1 )
- {
- NumToString( theInterleaveCount, &theSettings[ theLength ] );
- }
-
- else
- {
- GetComponentIndString(
- REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
- &theSettings[ theLength ], kRTPMPIMAAudioStringListResource,
- kRTPMPIMAAudioNoInterleavingString );
- }
-
- theSettings[ 0 ] += theSettings[ theLength ];
- theSettings[ theLength ] = theSavedCharacter;
- theLength = theSettings[ 0 ];
-
- *text = NewHandle( theLength );
-
- if( *text )
- BlockMoveData( &theSettings[ 1 ], **text, theLength );
- else
- theResult = MemError();
- }
-
- else
- {
- *text = 0;
- }
-
- return( theResult );
- }
-